<?php

namespace mini;

use Exception;

class Captcha
{
    private $width;                         //图片宽度
    private $height;                        //图片高度
    public  $bgcolor    = [255, 255, 255];  //背景颜色
    public  $codeColor  = [51, 51, 51];     //验证码颜色
    public  $fontSize   = 24;               //验证码字符大小
    private $totalChars = 4;                //总计字符数
    private $numbers    = 1;                //数字形式字符数量
    private $securityCode;                  //验证码内容
    public  $fontFamily  = null;            //字体文件路径
    public  $noise       = true;            //绘制干扰
    public  $sessionName = 'captcha';       //验证码在 Session 中储存的名称
    private $img         = null;            //绘图资源
    public  $noiseNumber = 6;

    /**
     * @param integer $width        图片宽度
     * @param integer $height       图片高度
     * @param integer $totalChars   总计字符数
     * @param integer $numbers      数字形式字符数量
     * @param string  $fontFamily   字体文件路径
     */
    public function __construct(int $width = 80, int $height = 40, int $totalChars = 4, int $numbers = 1, string $fontFamily = 'cuteaurora.ttf')
    {
        $this->fontFamily = __DIR__ . '/fonts/' . $fontFamily;
        $this->width      = $width;
        $this->height     = $height;
        $this->totalChars = $totalChars;
        $this->numbers    = $numbers;

        if ($this->fontFamily == null) {
            throw new Exception('验证码字体设置错误');
        }

        if (!is_file($this->fontFamily)) {
            throw new Exception('验证码字体文件不存在');
        }
    }

    /**
     * 设置显示的字符
     */
    private function setCharacters()
    {
        $strall = 'abcdefghjkmnpqrstwxyz';
        for ($i = 0; $i < ($this->totalChars - $this->numbers); $i++) {
            $text[] = $strall[mt_rand(0, 20)];
        }
        for ($i = 0; $i < $this->numbers; $i++) {
            $text[] = mt_rand(2, 9);
        }
        shuffle($text);
        $this->securityCode = implode('', $text);
        header('Content-type:image/png');
        $this->img = imagecreatetruecolor($this->width, $this->height);
    }


    /**
     * 绘制干扰
     */
    private function writeNoise()
    {
        $code  = '12345678abcdefhjkmnpqrstuvwxyz';
        for ($i = 0; $i < $this->noiseNumber; $i++) {
            $noiseColor = imagecolorallocate($this->img, mt_rand(150, 225), mt_rand(150, 225), mt_rand(150, 225));
            for ($j = 0; $j < 2; $j++) {
                imagestring($this->img, 5, mt_rand(-10, $this->width),  mt_rand(-10, $this->height), $code[mt_rand(0, 29)], $noiseColor);
            }
        }
    }

    /**
     * 生成验证码
     */
    public function make()
    {
        $this->setCharacters();
        Session::set($this->sessionName, $this->securityCode);

        $bgColor = imagecolorallocate(
            $this->img,
            $this->bgcolor[0],
            $this->bgcolor[1],
            $this->bgcolor[2]
        );

        imagefill($this->img, 0, 0, $bgColor);

        if ($this->noise) {
            $this->writeNoise();
        }

        $textColor = imagecolorallocate(
            $this->img, $this->codeColor[0],
            $this->codeColor[1],
            $this->codeColor[2]
        );
        $textFffset = imagettfbbox($this->fontSize, 0, $this->fontFamily, $this->securityCode);
        $fx = intval(($this->width - ($textFffset[2] - $textFffset[0])) / 2);
        $fy = $this->height - ($this->height - $this->fontSize) / 2;
        imagefttext($this->img, $this->fontSize, 0, $fx, $fy, $textColor, $this->fontFamily, $this->securityCode);
        imagepng($this->img);
        imagedestroy($this->img);
    }
}
